<template>
  <paas-content-loader
    :is-loading="isLoading"
    placeholder="deploy-inner-history-loading"
    :offset-top="0"
    :offset-left="-8"
    class="deploy-history m20"
  >
    <bk-form form-type="inline">
      <bk-form-item
        :label="$t('环境')"
        style="vertical-align: top;"
      >
        <bk-select
          v-model="choosedEnv"
          style="width: 150px;"
          :clearable="false"
        >
          <bk-option
            v-for="(option, index) in envList"
            :id="option.id"
            :key="index"
            :name="option.text"
          />
        </bk-select>
      </bk-form-item>
      <bk-form-item
        :label="$t('操作人')"
        style="vertical-align: top;"
      >
        <user
          v-model="personnelSelectorList"
          style="width: 350px;"
          :placeholder="$t('请选择')"
          :max-data="1"
        />
      </bk-form-item>
      <bk-form-item
        label=""
        style="vertical-align: top;"
      >
        <bk-button
          theme="primary"
          type="button"
          @click.stop.prevent="getDeployHistory(1)"
        >
          {{ $t('查询') }}
        </bk-button>
      </bk-form-item>
    </bk-form>
    <bk-table
      v-bkloading="{ isLoading: isPageLoading }"
      class="mt15 ps-history-list"
      :data="historyList"
      :outer-border="false"
      :size="'small'"
      :pagination="pagination"
      @row-click="handleShowLog"
      @page-limit-change="handlePageLimitChange"
      @page-change="handlePageChange"
    >
      <div slot="empty">
        <table-empty
          :keyword="tableEmptyConf.keyword"
          :abnormal="tableEmptyConf.isAbnormal"
          @reacquire="getDeployHistory"
          @clear-filter="clearFilter"
        />
      </div>
      <bk-table-column
        :label="$t('部署环境')"
        prop="name"
        :render-header="$renderHeader"
      >
        <template slot-scope="props">
          <span v-if="props.row.environment === 'stag'"> {{ $t('预发布环境') }} </span>
          <span v-else> {{ $t('生产环境') }} </span>
        </template>
      </bk-table-column>
      <bk-table-column
        width="150"
        :label="$t('分支')"
        prop="name"
        :show-overflow-tooltip="false"
      >
        <template slot-scope="props">
          <bk-popover>
            <span class="branch-name">{{ props.row.name }}</span>
            <div slot="content">
              <p class="flex">
                <span class="label"> {{ $t('部署分支：') }} </span><span class="value">{{ props.row.name }}</span>
              </p>
              <p class="flex">
                <span class="label"> {{ $t('仓库地址：') }} </span><span class="value">{{ props.row.url }}</span>
              </p>
            </div>
          </bk-popover>
        </template>
      </bk-table-column>
      <!-- <bk-table-column label="部署目录">
                <template slot-scope="{ row }">
                    {{ row.source_dir || '--' }}
                </template>
            </bk-table-column> -->
      <bk-table-column
        :label="$t('版本')"
        prop="revision"
        :show-overflow-tooltip="true"
      />
      <bk-table-column
        :label="$t('操作人')"
        prop="operator.username"
        :render-header="$renderHeader"
      />
      <bk-table-column
        :label="$t('类型')"
        prop="operation_act"
        :render-header="$renderHeader"
      />
      <bk-table-column
        :label="$t('耗时')"
        :render-header="$renderHeader"
      >
        <template slot-scope="{ row }">
          {{ computedDeployTime(row) }}
        </template>
      </bk-table-column>
      <bk-table-column :label="$t('结果')">
        <template slot-scope="props">
          <div v-if="props.row.status === 'successful'">
            <span class="dot success" /> {{ $t('成功') }}
          </div>
          <div v-if="props.row.status === 'failed'">
            <span class="dot danger" /> {{ $t('失败') }}
          </div>
          <div v-if="props.row.status === 'interrupted'">
            <span class="dot warning" /> {{ $t('中断') }}
          </div>
          <div v-if="props.row.status === 'pending' && props.row.operation_type === 'online'">
            <span class="dot warning" /> {{ $t('部署中') }}
          </div>
          <div v-if="props.row.status === 'pending' && props.row.operation_type === 'offline'">
            <span class="dot warning" /> {{ $t('下架中') }}
          </div>
        </template>
      </bk-table-column>
      <bk-table-column
        width="180"
        :label="$t('操作时间')"
        prop="created"
      />
    </bk-table>

    <bk-sideslider
      :title="historySideslider.title"
      :width="920"
      :is-show.sync="historySideslider.isShow"
      :quick-close="true"
      @hidden="errorTips = {}"
    >
      <div
        slot="content"
        v-bkloading="{ isLoading: isLogLoading || isTimelineLoading, opacity: 1 }"
        class="deploy-detail"
      >
        <template v-if="!(isLogLoading || isTimelineLoading)">
          <deploy-timeline
            v-if="timeLineList.length"
            :list="timeLineList"
            :disabled="true"
            class="mt20 ml15 mr15"
            style="min-width: 250px;"
          />
          <div class="paas-log-box">
            <div
              v-if="isMatchedSolutionsFound"
              class="wrapper danger"
            >
              <div class="fl">
                <span class="paasng-icon paasng-info-circle-shape" />
              </div>
              <section style="position: relative; margin-left: 50px;">
                <p class="deploy-pending-text">
                  {{ $t('部署失败') }}
                </p>
                <p class="deploy-text-wrapper">
                  <span class="reason mr5">{{ errorTips.possible_reason }}</span>
                  <span
                    v-for="(help, index) in errorTips.helpers"
                    :key="index"
                  >
                    <a
                      :href="help.link"
                      target="_blank"
                      class="mr10"
                    >
                      {{ help.text }}
                    </a>
                  </span>
                </p>
              </section>
            </div>
            <bk-alert
              v-else
              style="margin: -20px -20px 10px -20px; border-radius: 0;"
              type="warning"
              :title="$t('仅展示准备阶段、构建阶段日志')"
            />
            <pre v-html="curDeployLog" />
          </div>
        </template>
      </div>
    </bk-sideslider>
  </paas-content-loader>
</template>

<script>
    import appBaseMixin from '@/mixins/app-base-mixin';
    import deployTimeline from './comps/deploy-timeline';
    import user from '@/components/user';

    export default {
        components: {
            user,
            deployTimeline
        },
        mixins: [appBaseMixin],
        data () {
            return {
                choosedEnv: 'all',
                historyList: [],
                curDeployLog: '',
                logDetail: '',
                isLoading: true,
                isPageLoading: true,
                isLogLoading: false,
                isTimelineLoading: false,
                ansiUp: null,
                personnelSelectorList: [],
                formDatas: {},
                pagination: {
                    current: 1,
                    count: 0,
                    limit: 10
                },
                envList: [
                    {
                        id: 'all',
                        text: this.$t('全部')
                    },
                    {
                        id: 'prod',
                        text: this.$t('生产环境')
                    },
                    {
                        id: 'stag',
                        text: this.$t('预发布环境')
                    }
                ],
                timeLineList: [],
                historySideslider: {
                    title: '',
                    isShow: false
                },
                errorTips: {},
                tableEmptyConf: {
                    keyword: '',
                    isAbnormal: false
                }
            };
        },
        computed: {
            isMatchedSolutionsFound () {
                return this.errorTips.matched_solutions_found;
            }
        },
        watch: {
            '$route': function () {
                this.isLoading = true;
                this.getDeployHistory();
            }
        },
        created () {
            this.isLoading = true;
            this.getDeployHistory();
        },
        mounted () {
            const AU = require('ansi_up');
            // eslint-disable-next-line
            this.ansiUp = new AU.default
        },
        methods: {
            updateValue (curVal) {
                curVal ? this.personnelSelectorList = curVal : this.personnelSelectorList = '';
            },

            computedDeployTime (payload) {
                if (!payload.deployment) {
                    return '--';
                }

                if (!payload.deployment.complete_time || !payload.deployment.start_time) {
                    return '--';
                }

                const start = new Date(payload.deployment.start_time).getTime();
                const end = new Date(payload.deployment.complete_time).getTime();
                const interval = (end - start) / 1000;

                if (!interval) {
                    return `< 1${this.$t('秒')}`;
                }

                return this.getDisplayTime(interval);
            },

            computedDeployTimelineTime (startTime, endTime) {
                if (!startTime || !endTime) {
                    return '--';
                }

                const start = (new Date(startTime).getTime()) / 1000;
                const end = (new Date(endTime).getTime()) / 1000;
                const interval = Math.ceil(end - start);

                if (!interval) {
                    return `< 1${this.$t('秒')}`;
                }

                return this.getDisplayTime(interval);
            },

            getDisplayTime (payload) {
                let theTime = payload;
                if (theTime < 1) {
                    return `< 1${this.$t('秒')}`;
                }
                let middle = 0;
                let hour = 0;

                if (theTime > 60) {
                    middle = parseInt(theTime / 60, 10);
                    theTime = parseInt(theTime % 60, 10);
                    if (middle > 60) {
                        hour = parseInt(middle / 60, 10);
                        middle = parseInt(middle % 60, 10);
                    }
                }

                let result = '';

                if (theTime > 0) {
                    result = `${theTime}${this.$t('秒')}`;
                }
                if (middle > 0) {
                    result = `${middle}${this.$t('分')}${result}`;
                }
                if (hour > 0) {
                    result = `${hour}${this.$t('时')}${result}`;
                }

                return result;
            },

            /**
             * 获取部署记录
             */
            async getDeployHistory (page = 1) {
                this.isPageLoading = true;
                const curPage = page || this.pagination.current;
                const pageParams = {
                    limit: this.pagination.limit,
                    offset: this.pagination.limit * (curPage - 1)
                };
                if (this.choosedEnv !== 'all') {
                    pageParams.environment = this.choosedEnv;
                }

                if (this.personnelSelectorList.length) {
                    pageParams.operator = this.personnelSelectorList[0];
                }

                try {
                    const res = await this.$store.dispatch('deploy/getDeployHistory', {
                        appCode: this.appCode,
                        moduleId: this.curModuleId,
                        pageParams
                    });

                    const reg = RegExp('^[a-z0-9]{40}$');
                    res.results.forEach((operation) => {
                        if (operation.operation_type === 'offline') {
                            operation.logDetail = operation.offline_operation.log;
                            operation.operation_act = this.$t('下架');
                            operation.environment = operation.offline_operation.environment;

                            operation.name = operation.offline_operation.repo.name;
                            operation.revision = operation.offline_operation.repo.revision;
                            operation.url = operation.offline_operation.repo.url;

                            if (reg.test(operation.offline_operation.repo.revision)) {
                                operation.revision = operation.offline_operation.repo.revision.substring(0, 8);
                            }
                        } else {
                            operation.deployment_id = operation.deployment.deployment_id;
                            operation.environment = operation.deployment.environment;
                            operation.logDetail = '';
                            operation.operation_act = this.$t('部署');

                            operation.name = operation.deployment.repo.name;
                            operation.revision = operation.deployment.repo.revision;
                            operation.url = operation.deployment.repo.url;

                            if (reg.test(operation.deployment.repo.revision)) {
                                operation.revision = operation.deployment.repo.revision.substring(0, 8);
                            }
                        }
                    });
                    this.historyList = res.results;
                    this.pagination.count = res.count;

                    // 如果有deployid，默认显示
                    if (this.$route.query.deployId) {
                        const recordItem = this.historyList.find(item => {
                            return item.deployment_id === this.$route.query.deployId;
                        });
                        if (recordItem) {
                            this.handleShowLog(recordItem);
                        }
                    }
                    this.updateTableEmptyConfig();
                    this.tableEmptyConf.isAbnormal = false;
                } catch (e) {
                    this.tableEmptyConf.isAbnormal = true;
                    this.$paasMessage({
                        theme: 'error',
                        message: e.detail || e.message
                    });
                } finally {
                    this.isLoading = false;
                    this.isPageLoading = false;
                }
            },

            handlePageLimitChange (limit) {
                this.pagination.limit = limit;
                this.pagination.current = 1;
                this.getDeployHistory(this.pagination.current);
            },

            handlePageChange (newPage) {
                this.pagination.current = newPage;
                this.getDeployHistory(newPage);
            },

            handleShowLog (row) {
                this.timeLineList = [];
                this.curDeployLog = '';
                if (this.isTimelineLoading || this.isLogLoading) {
                    return false;
                }

                const operator = row.operator.username;
                const time = row.created;
                if (row.operation_type === 'offline') {
                    const title = `${row.environment === 'prod' ? this.$t('生产环境') : this.$t('预发布环境')}${this.$t('下架日志')} (${operator}${this.$t('于')}${time}${this.$t('下架')}`;
                    this.historySideslider.title = title;
                    this.curDeployLog = row.logDetail;
                } else {
                    const branch = row.name;
                    this.historySideslider.title = `${row.environment === 'prod' ? this.$t('生产环境') : this.$t('预发布环境')}${this.$t('部署日志')} (${operator}${this.$t('于')}${time}${this.$t('部署')}${branch}${this.$t('分支')})`;
                    this.getDeployTimeline(row);
                    this.getDeployLog(row);
                }
                this.historySideslider.isShow = true;
            },

            async getDeployTimeline (params) {
                if (this.isTimelineLoading) {
                    return false;
                }

                this.isTimelineLoading = true;
                try {
                    const res = await this.$store.dispatch('deploy/getDeployTimeline', {
                        appCode: this.appCode,
                        moduleId: this.curModuleId,
                        env: params.environment,
                        deployId: params.deployment_id
                    });
                    const timeLineList = [];
                    res.forEach(stageItem => {
                        timeLineList.push({
                            tag: stageItem.display_name,
                            content: this.computedDeployTimelineTime(stageItem.start_time, stageItem.complete_time),
                            status: stageItem.status || 'default',
                            stage: stageItem.type
                        });

                        stageItem.steps.forEach(stepItem => {
                            timeLineList.push({
                                tag: stepItem.display_name,
                                content: this.computedDeployTimelineTime(stepItem.start_time, stepItem.complete_time),
                                status: stepItem.status || 'default',
                                parentStage: stageItem.type
                            });
                        });
                    });
                    this.timeLineList = timeLineList;
                } catch (e) {
                    this.timeLineList = [];
                } finally {
                    this.isTimelineLoading = false;
                }
            },

            async getDeployLog (params) {
                if (this.isLogLoading) {
                    return false;
                }
                this.isLogLoading = true;
                console.log(this.isLogLoading);
                try {
                    const res = await this.$store.dispatch('deploy/getDeployLog', {
                        appCode: this.appCode,
                        moduleId: this.curModuleId,
                        env: params.environment,
                        deployId: params.deployment_id
                    });
                    this.curDeployLog = this.ansiUp ? this.ansiUp.ansi_to_html(res.logs) : res.logs;
                    this.errorTips = Object.assign({}, res.error_tips);
                } catch (e) {
                    this.curDeployLog = '';
                    this.$paasMessage({
                        theme: 'error',
                        message: e.detail || e.message
                    });
                } finally {
                    this.isLogLoading = false;
                }
            },

            clearFilter () {
                this.choosedEnv = 'all';
                this.personnelSelectorList = [];
                this.getDeployHistory();
            },

            updateTableEmptyConfig () {
                if (this.personnelSelectorList.length || this.choosedEnv !== 'all') {
                    this.tableEmptyConf.keyword = 'placeholder';
                    return;
                }
                this.tableEmptyConf.keyword = '';
            }
        }
    };
</script>

<style lang="scss" scoped>
    .deploy-history {
        min-height: 500px !important;
    }
    .dot {
        width: 8px;
        height: 8px;
        border-radius: 50%;
        display: inline-block;
        margin-right: 5px;

        &.success {
            background: #a0f5e3;
            border: 1px solid #18c0a1;
        }

        &.danger {
            background: #fd9c9c;
            border: 1px solid #ea3636;
        }

        &.warning {
            background: #FFE8C3;
            border: 1px solid #FF9C01;
        }
    }

    .wrapper {
        margin: -20px -20px 10px;
        height: 64px;
        background: #F5F6FA;
        line-height: 64px;
        padding: 0 20px;

        &::after {
            display: block;
            clear: both;
            content: "";
            font-size: 0;
            height: 0;
            visibility: hidden;
        }

        &.default-box {
            padding: 11px 12px 11px 20px;
            height: auto;
            line-height: 16px;
            .span {
                height: 16px;
            }
        }

        &.not-deploy {
            height: 42px;
            line-height: 42px;
        }

        &.primary {
            background: #E1ECFF;
            color: #979BA5;
        }

        &.warning {
            background: #FFF4E2;
            border-color: #FFDFAC;

            .paasng-icon {
                color: #fe9f07;
            }
        }

        &.danger {
            background: #FFECEC;
            color: #979BA5;

            .paasng-icon {
                color: #eb3635;
                position: relative;
                top: 4px;
                font-size: 32px;
            }
        }

        &.success {
            background: #E7FCFA;
            color: #979BA5;

            .paasng-icon {
                position: relative;
                top: 4px;
                color: #3fc06d;
                font-size: 32px;
            }
        }
        .deploy-pending-text {
            position: relative;
            top: 5px;
            font-size: 14px;
            color: #313238;
            font-weight: 500;
            line-height: 32px;
        }
        .deploy-text-wrapper {
            position: relative;
            top: -5px;
            line-height: 32px;
            font-size: 12px;
            .branch-text,
            .version-text,
            .time-text {
                font-size: 12px;
                color: #63656e;
                opacity: .9;
            }
            .branch-text,
            .version-text {
                margin-right: 30px;
            }
        }
    }

    .deploy-detail {
        display: flex;
        height: 100%;

        /deep/ .paas-deploy-log-wrapper {
            height: 100%;
        }
    }

    .flex {
        display: flex;
        line-height: 16px;
        margin-bottom: 3px;

        .label {
            display: inline-block;
            width: 60px;
        }

        .value {
            text-align: left;
            display: inline-block;
            flex: 1;
        }
    }

    .branch-name {
        width: 130px;
        display: block;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
</style>
